/**
 * 
 */
package com.zte.claa.inficombo.csa.app.comm.csif.mina;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;

import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.future.WriteFuture;
import org.apache.mina.core.service.IoConnector;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.zte.claa.inficombo.csa.app.comm.csif.CSIFCommService;
import com.zte.claa.inficombo.csa.app.comm.csif.mina.msg.CSIFMessage;
import com.zte.claa.inficombo.csa.app.config.CSIFCommProps;
import com.zte.claa.inficombo.csa.app.model.app.AppTarget;

/**
 * @author lyp
 */
public class CSIFMinaConnManager {
	private static Logger logger = LoggerFactory.getLogger(CSIFMinaConnManager.class);  
	
	// 到CSIF的mina连接参数.
	private CSIFCommProps csifCommProps;
	private AppTarget appTarget;
	private CSIFCommService csifCommService = null;
	private IoConnector connector = null;
	private IoSession session = null; 
	
	/**
	 * 构建器。
	 *
	 */
	public CSIFMinaConnManager(CSIFCommProps csifCommProps, AppTarget appTarget, CSIFCommService iotmCommService){
		this.csifCommProps = csifCommProps;
		this.appTarget = appTarget;
		this.csifCommService = iotmCommService;
	}
	
	/**
	 * 创建连接
	 * @throws Exception
	 */
	public void createConnect() throws Exception {
		String host = "";
		int port = 0;
		try {
			// 创建connector
			connector = new NioSocketConnector();
			// 超时等待。
			connector.setConnectTimeoutMillis(this.csifCommProps.getConnwaitsecond() * 1000L);
			// 实例化编解码器。
			CSIFMsgDecoder decoder = new CSIFMsgDecoder(Charset.forName(this.csifCommProps.getCharsetname()));
			CSIFMsgEncoder encoder = new CSIFMsgEncoder(Charset.forName(this.csifCommProps.getCharsetname()));
			CSIFMsgCodecFactory codecFactory = new CSIFMsgCodecFactory(decoder, encoder);
			// 添加到过滤链。
			connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(codecFactory));
			// 设置handler
			connector.setHandler(new CSIFMinaClientHandler(this.csifCommService));
			connector.getSessionConfig().setReadBufferSize(this.csifCommProps.getBufsize());
			// 设置空闲状态（1分钟无上报消息，则认为session空闲，需要检查心跳消息，连续三个心跳周期无上报，则断链重连。注：这里仅检测上报消息。）
			connector.getSessionConfig().setIdleTime(IdleStatus.READER_IDLE, this.csifCommProps.getSessionidlesecond());
			// 连接到服务器。
			host = this.appTarget.getCsifIpAddr();
			port = this.appTarget.getCsifPort();
			ConnectFuture future = connector.connect(new InetSocketAddress(host, port));
			// 等待连接完成
			future.awaitUninterruptibly();
			// 获取session
			session = future.getSession();
			logger.info("Connect to CSIF succ: "+appTarget.getCsifIpAddr()+", port="+this.appTarget.getCsifPort());
		}catch(Exception e){	
			logger.error("Create connection to CSIF failed: "+host+":"+port, e);
			if(this.session != null){
				// this.session.close(true);
				this.session.closeNow();
				this.session = null;
			}
			if(this.connector != null){
				this.connector.dispose();
				this.connector = null;
			}				
			throw new Exception("无法连接目标主机："+host+":"+port, e);
		}
	}
	
	/**
	 * 下发命令。
	 * @param cmd
	 * @throws Exception
	 */
	public WriteFuture sendCommand(CSIFMessage cmd) throws Exception {
		if(session == null){
			throw new Exception("通信链路会话为空，网络不可达！");
		}
		return this.session.write(cmd);  
		/**
		 * 增加如下代码会报：DEAD LOCK:IoFuture.await()wasinvokedfromanI/Oprocessorthread
		WriteFuture wf = session.write(cmd);  
		wf.awaitUninterruptibly(this.csifCommProps.getCmdsendtimeoutsecond() * 1000L);
		if(!wf.isWritten()){
			String err = "消息下发超时！";
			Throwable t = wf.getException();
			if(t != null){
				err = t.getMessage();
			}
			throw new Exception("消息下发失败："+err+", cmd=["+cmd.toString()+"]");
		}
		*/
		
	}

	/**
	 * 释放session和connector.
	 */
	public void releaseConnection() {
		if(session != null && !session.isClosing()){
			// session.close(true);
			session.closeNow();
			this.session = null;
			logger.info("releaseConnection() -- close session. ");			
		}
		if(this.connector != null){
			this.connector.dispose();
			this.connector = null;
			logger.info("releaseConnection() -- close connector. ");
		}
	}
	
}
